package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.AlertDataMapper;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.service.IAlertRuleService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.net.http.WebSocket;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * 报警规则Service业务层处理
 *
 * @author ruoyi
 * @date 2025-01-17
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService {
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private AlertDataMapper alterDataMapper;

    @Autowired
    private IAlertDataService iAlertDataService;

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 查询报警规则
     *
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id) {
        return getById(id);
    }

    /**
     * 查询报警规则列表
     *
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule) {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule) {
        return save(alertRule) ? 1 : 0;
    }

    /**
     * 修改报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule) {
        return updateById(alertRule) ? 1 : 0;
    }

    /**
     * 批量删除报警规则
     *
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除报警规则信息
     *
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    //新增定时任务类，启动数据过滤
    @Override
    public void alertFilter() {
        //查询所有规则，遍历规则
        long count = count(new LambdaQueryWrapper<AlertRule>()
                .eq(AlertRule::getStatus, 1));
        if (count < 1) {
            return;
        }
        List<Object> values = redisTemplate.opsForHash().values("iot:device_last_data");
        if (CollUtil.isEmpty(values)) {
            return;
        }
        //解析拿到的所有上报数据，存入到一个新的集合中，包含了所有的模型数据
        List<DeviceData> deviceDataList = new ArrayList<>();
        values.forEach(value -> {
            List<DeviceData> list = JSONUtil.toList(value.toString(), DeviceData.class);
            deviceDataList.addAll(list);
        });
        if (CollUtil.isEmpty(deviceDataList)) {
            return;
        }
        //遍历拿到的IOT上报数据，去匹配 告警 规则
        deviceDataList.forEach(deviceData -> {
            alertRuleData(deviceData);
        });
    }


    private void alertRuleData(DeviceData deviceData) {
        //1.查询所有的关联设备的报警规则
        List<AlertRule> allAlertRuleList = this.list(new LambdaQueryWrapper<AlertRule>()
                .eq(AlertRule::getProductKey, deviceData.getProductKey())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                .eq(AlertRule::getIotId, -1)
                .eq(AlertRule::getStatus, 1));
        //2.查询该设备报警规则
        List<AlertRule> AlertRuleList = this.list(new LambdaQueryWrapper<AlertRule>()
                .eq(AlertRule::getProductKey, deviceData.getProductKey())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                .eq(AlertRule::getIotId, deviceData.getIotId())
                .eq(AlertRule::getStatus, 1));
        //3.合并所有规则
        allAlertRuleList.addAll(AlertRuleList);
        if (CollUtil.isEmpty(allAlertRuleList)) {
            return;
        }
        ;
        //4.遍历数据，判断是否满足规则
        allAlertRuleList.forEach(alertRule -> {
            alterRuleHandler(alertRule, deviceData);
        });
    }

    private void alterRuleHandler(AlertRule alertRule, DeviceData deviceData) {
        // 1.判断当前时间是否在生效时间范围内

        LocalTime time = deviceData.getAlarmTime().toLocalTime();
        //  00:00:00-23:59:59
        String alertEffectivePeriod = alertRule.getAlertEffectivePeriod();
        String[] split = alertEffectivePeriod.split("~");
        LocalTime startTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        if (time.isBefore(startTime) || time.isAfter(endTime)) {
            return;
        }

        // 2.判断数据是否达到阈值
        Double dataValue = Double.valueOf(deviceData.getDataValue());
        Double value = alertRule.getValue();
        // x>y=1,x<y=-1,x=y=0
        int compare = CompareUtil.compare(dataValue, value);
        if ((alertRule.getOperator().equals(">=") && compare >= 0) || (alertRule.getOperator().equals("<") && compare < 0)) {
            log.info("设备数据满足告警规则");
        } else {
            //TODO   //删除报警
            redisTemplate.delete("iot:duration" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
            return;
        }

        // 3.判断沉默周期
        String silent = redisTemplate.opsForValue().get("iot:silent:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
        if (ObjectUtil.isNotEmpty(silent)) {
            return;
        }
        //  4.判断持续周期
        String count = redisTemplate.opsForValue().get("iot:duration" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
        int sum = count == null ? 1 : Integer.valueOf(count) + 1;
        if (!alertRule.getDuration().equals(sum)) {
            redisTemplate.opsForValue().set("iot:duration" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId(), sum + "");
            return;
        }
        // 5.
        redisTemplate.delete("iot:duration" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId());
        //  6.添加沉默周期
        redisTemplate.opsForValue().set("iot:silent:" + deviceData.getIotId() + ":" + deviceData.getFunctionId() + ":" + alertRule.getId(), "1", alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);
        //7.校验完成
        List<Long> userIds = null;
        if (alertRule.getAlertDataType().equals(0)) { //老人手表
            if (deviceData.getLocationType().equals(0)) {//床
                userIds = deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());//获取nursingId
            } else {
                userIds = deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
            }
        } else {
            //查询维修工
            userIds = deviceMapper.selectUserIdByRoleName("维修工");
        }
        //发送一份给超级管理员
        List<Long> managers = deviceMapper.selectUserIdByRoleName("超级管理员");
        Collection<Long> addAll = CollUtil.addAll(userIds, managers);
        List<Long> idList = CollUtil.distinct(addAll);
        insertBathRuleData(idList, alertRule, deviceData);
    }

    private void insertBathRuleData(List<Long> idList, AlertRule alertRule, DeviceData deviceData) {

        AlertData alterData = BeanUtil.toBean(deviceData, AlertData.class);
        alterData.setAlertRuleId(alertRule.getId());
        alterData.setAlertReason(alertRule.getFunctionName() + alertRule.getOperator() + ",持续" + alertRule.getValue() + "阈值" + alertRule.getDuration());
        alterData.setType(deviceData.getLocationType());
        alterData.setStatus(0);
        alterData.setAccessLocation(deviceData.getAccessLocation());
        alterData.setProductName(deviceData.getProductName());


        List<AlertData> alterDataList = new ArrayList<>();
        idList.forEach(id -> {
            AlertData bean = BeanUtil.toBean(alterData, AlertData.class);
            bean.setId(null);
            bean.setUserId(id);
            alterDataMapper.insertAlertData(bean);
        });
        iAlertDataService.saveBatch(alterDataList);

        //推送消息给护理员
        // websocket推送消息
        //属性拷贝
        AlertNotifyVo alertNotifyVo = BeanUtil.toBean(alterDataList, AlertNotifyVo.class);
        alertNotifyVo.setFunctionName(alertRule.getFunctionName());
        alertNotifyVo.setAlertDataType(alertRule.getAlertDataType());
        alertNotifyVo.setNotifyType(1);
        alertNotifyVo.setAccessLocation(deviceData.getAccessLocation());
        alertNotifyVo.setFunctionName(alertRule.getFunctionName());
        alertNotifyVo.setProductName(alertRule.getProductName());
        alertNotifyVo.setDataValue(alterData.getDataValue());
        //向指定的人推送消息
        webSocketServer.sendMessageToConsumer(alertNotifyVo, idList);
    }
}
